<?php

namespace Tictactoe\Ai;

use Tictactoe\Game as Game;
use Tictactoe\Tool as Tool;
use Tictactoe\Ai\Population\Item as Item;

class Population {
    
    /**
     * @var Item[]
     */
    protected $items = array();
    
    /**
     * @var int 
     */
    protected $populationQty = 50;

    /**
     * @var bool
     */
    protected $oponentOwnerFlag = false;
    
    /**
     * @var Item[]
     */
    protected $oponentAlmostWinItems = array();
    
    public function getOponentAlmostWinItems() {
        return $this->oponentAlmostWinItems;
    }

    /**
     * @param Item $item
     */
    public function addOponentAlmostWinItem(Item $item) {
        $this->oponentAlmostWinItems[] = $item;
    }
    
    public function getOponentOwnerFlag() {
        return $this->oponentOwnerFlag;
    }

    public function setOponentOwnerFlag($oponentOwnerFlag) {
        $this->oponentOwnerFlag = $oponentOwnerFlag;
    }
    
    /**
     * @return int
     */
    public function getPopulationQty() {
        return $this->populationQty;
    }

    /**
     * @param int $populationQty
     */
    public function setPopulationQty($populationQty) {
        $this->populationQty = $populationQty;
    }

    public function getItems() {
        return $this->items;
    }
    
    public function delItem($key) {
        unset($this->items[$key]);
    }
    
    /**
     * @param Game $game
     * @param int $moveX
     * @param int $moveY
     * @param int $value
     */
    public function addItem(Game $game, $moveX, $moveY, $value) {
        
        $estimate = new Estimate($game, $moveX, $moveY, $this->getOponentOwnerFlag());
        
        try {
            $estimateValue = $estimate->getEstimateForValue($value);

            $item = new Item($game, $moveX, $moveY, $value, $estimateValue );
            
            $this->items[] = $item;

            usort($this->items, function ($a, $b) {
                $a = $a->getEstimate();
                $b = $b->getEstimate();

                if ($a == $b) {
                    return 0;
                }
                return ($a > $b) ? -1 : 1;
            });

            $this->items = array_slice($this->items, 0, $this->getPopulationQty());
        } catch (Exception\EstimateOponentAlmostWin $e) {
            
            /**
             * wypelnienie tablicy z mozliwymi zwycieskimi ruchami przeciwnika
             * dla ktorych liczona jest estymacja
             * a nastepnie najlepszy ruch przeciwnika przejmowany jest przez algorytm
             */
            
            $estimate->setOponentOwnerFlag(false);
            $estimateValue = $estimate->getEstimateForValue($value);
            
            $playerValue = Tool::getOponentValue($value);
            $item = new Item($game, $moveX, $moveY, $playerValue, $estimateValue );
            $this->addOponentAlmostWinItem($item);
            
        } catch (Exception\EstimateWinner $e) {
            $item = new Item($game, $moveX, $moveY, $value, 'winner' );
            $e->setPopulationItem($item);
            throw $e;
        }
    }

}
